﻿using Microsoft.Win32;
using SUNRPA.CONTROLS.IMPL.domain;
using SUNRPA.CONTROLS.IMPL.domain.constant;
using System.Configuration;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Windows;
/// <summary>
/// 系统工具，包括windows的一些基本功能，例如登录休眠关机等
/// </summary>
namespace SUNRPA.CONTROLS.IMPL.util {
    public class SystemUtil {
        public static List<RegistryKey> softWareList = GetSoftWareList();
        //获取软件列表
        private static List<RegistryKey> GetSoftWareList() { 
            List<RegistryKey> list = new List<RegistryKey>(); 
            string UninstallKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
            RegistryKey regUninstall = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(UninstallKey, false);
            GetSubSoftWare(regUninstall, ref list);
            regUninstall.Dispose();
            regUninstall = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(UninstallKey, false);
            GetSubSoftWare(regUninstall, ref list);
            regUninstall.Dispose();
            regUninstall = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry32).OpenSubKey(UninstallKey, false);
            GetSubSoftWare(regUninstall, ref list);
            regUninstall.Dispose();
            regUninstall = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64).OpenSubKey(UninstallKey, false);
            GetSubSoftWare(regUninstall, ref list);
            regUninstall.Dispose();
            return list;
        }

        private static void GetSubSoftWare(RegistryKey registryKey, ref List<RegistryKey> list) { 
            foreach (string keyName in registryKey.GetSubKeyNames()) { 
                RegistryKey subkey = registryKey.OpenSubKey(keyName);
                string displayName = subkey.GetValue("DisplayName") as string;
                string installLocation = subkey.GetValue("InstallLocation") as string;
                string uninstallString = subkey.GetValue("UninstallString") as string;
                if(String.IsNullOrEmpty(displayName)) { 
                    continue;
                }
                list.Add(subkey);
            }
        }

        /// <summary>
        /// 注册表中获取可执行文件路径
        /// </summary>
        /// <param name="executeName">可执行文件名称</param>
        /// <returns></returns>
        public static string GetExecutePath(string executeName) {
            if(string.IsNullOrWhiteSpace(executeName)){
                return string.Empty;
            }
            string strKeyName = string.Empty;
            string appPath = string.Empty;
            if(executeName.IndexOf(".exe", StringComparison.OrdinalIgnoreCase) == -1){
                executeName = $"{executeName}.exe";
            }
            string softPath = $@"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\{executeName}";
            RegistryKey regSubKey = Registry.LocalMachine.OpenSubKey(softPath, false);
            if(regSubKey != null) {
                object objResult = regSubKey.GetValue(strKeyName);
                RegistryValueKind regValueKind = regSubKey.GetValueKind(strKeyName);
                if(regValueKind == RegistryValueKind.String) {
                    appPath = objResult?.ToString();
                }
            }
            return appPath;
        }
        public static SoftWareInfo FindSoftWareByName(String name) { 
            RegistryKey key = softWareList.FirstOrDefault(key => name.Equals(key.GetValue("DisplayName").ToString()));
            if(key == null) { 
                return new SoftWareInfo();
            }
            string displayName = key.GetValue("DisplayName") as string;
            string installLocation = key.GetValue("InstallLocation") as string;
            string uninstallString = key.GetValue("UninstallString") as string;
            string displayVersion = key.GetValue("DisplayVersion") as string;
            string installDate = key.GetValue("InstallDate") as string;
            string publisher = key.GetValue("Publisher") as string;
            string displayIcon = key.GetValue("DisplayIcon") as string;
            SoftWareInfo softWareInfo = new SoftWareInfo() {DisplayName = displayName,
                InstallLocation = installLocation, DisplayVersion = displayVersion, UninstallString = uninstallString};
            return softWareInfo;
        }
        public static SoftWareInfo FindSoftWareByFuzzyMatching(String name) { 
            RegistryKey key = softWareList.FirstOrDefault(key => key.GetValue("DisplayName").ToString().ToLower().Contains(name.ToLower()));
            if(key == null) { 
                return new SoftWareInfo();
            }
            string displayName = key.GetValue("DisplayName") as string;
            string installLocation = key.GetValue("InstallLocation") as string;
            string uninstallString = key.GetValue("UninstallString") as string;
            string displayVersion = key.GetValue("DisplayVersion") as string;
            string installDate = key.GetValue("InstallDate") as string;
            string publisher = key.GetValue("Publisher") as string;
            string displayIcon = key.GetValue("DisplayIcon") as string;
            SoftWareInfo softWareInfo = new SoftWareInfo() {DisplayName = displayName,
                InstallLocation = installLocation, DisplayVersion = displayVersion, UninstallString = uninstallString};
            return softWareInfo;
        }

        //通过programId（vb时期没有命名空间只有programId）创建com对象
        public static object CreateComObj(string progId) { 
           return Microsoft.VisualBasic.Interaction.CreateObject(progId);
        }
        //获取com对象实际类型
        public static string GetTypeOfCom(object comObj) { 
            return Microsoft.VisualBasic.Information.TypeName(comObj);
        }

        //获取COM的ROT
        public static IRunningObjectTable? GetROT4Com() { 
            int retVal = User32Utils.GetRunningObjectTable(0, out IRunningObjectTable rot);
            if(retVal == 0) {
                return rot;
            } else { 
                return null;
            }
        }

        //根据guid获取特定的已存在的COM对象
        public static void GetSpecificComObjByGuid(string guid, IRunningObjectTable rot, out object? obj){ 
            obj = null;
            rot.EnumRunning(out IEnumMoniker enumMoniker);
            var moniker = new IMoniker[1];
            while (enumMoniker.Next(1, moniker, IntPtr.Zero) == 0){
                User32Utils.CreateBindCtx(0, out IBindCtx bindCtx);
                moniker[0].GetDisplayName(bindCtx, null, out string displayName);
                rot.GetObject(moniker[0], out object comObj);
                string id = ConversionGuid(displayName);
                if(guid.ToLower().Equals(id.ToLower())) { 
                    obj = comObj;
                    break;
                }
            }
        }

        public static string? ConversionGuid(string displayName){
            if(string.IsNullOrEmpty(displayName)) { 
                return null;
            }
            string guid = null;
            try{
                displayName = displayName.Substring(2, displayName.Length - 3);
                guid = displayName;
            }catch { 
                //log
            }
            return guid;
        }

        /// <summary>
        /// 通过软软件注册表获取特定已注册软件的信息
        /// </summary>
        /// <param name="progId">progId</param>
        /// <param name="verName">软件版本</param>
        public static List<Guid> GetGuidKeys(string progId, [Optional]string version){
            string appReg = progId;
            string appRegDot = appReg + ".";
            //var fmts = new string[] { @"Software\Classes", @"Software\Wow6432Node\Classes" };
            var fmts = new string[] { @"Software\Classes" };//只需要在32位上面找
            List<Guid> keys = new List<Guid>();
            foreach (var fmt in fmts){
                var classes = Registry.LocalMachine.OpenSubKey(fmt);
                if (classes == null){
                    continue;
                }
                foreach (string verReg in classes.GetSubKeyNames()){
                    try{
                        if (verReg.Contains(appReg)){
                            var app = classes.OpenSubKey(verReg);
                            if (app == null) { 
                                continue;
                            }
                            var clsid = app.OpenSubKey("CLSID");
                            if (clsid == null){ 
                                continue;
                            } 
                            var verStr = verReg.Replace(appRegDot, string.Empty);
                            double.TryParse(verStr, out double verNumber);
                            if(!string.IsNullOrEmpty(version) && version.Equals(verNumber)) { 
                                keys.Add(new Guid(clsid.GetValue(null).ToString()));
                            }else if(string.IsNullOrEmpty(version)) { 
                                keys.Add(new Guid(clsid.GetValue(null).ToString()));
                            }
                        }
                    }catch{
                        //log
                    }
                }
            }
            return keys;
        }

        /// <summary>
        /// 获取app.config内的配置信息
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetAPPConfig(string key) { 
            return ConfigurationManager.AppSettings[key];
        }

        public static string GetLastErrorMsg() { 
            int errCode = Marshal.GetLastWin32Error();
            return User32Utils.GetSysErrMsg(errCode);
        }

        public static double GetSysyemZoomSize() {
            //获取桌面设备
            IntPtr deskH = User32Utils.GetDesktopWindow();
            IntPtr desktop = User32Utils.GetDC(deskH);
            //获取桌面物理高度
            var physicalScreenHeight = GDIUtils.GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES);
            GDIUtils.DeleteDC(desktop);
            //物理高度除以实际高度为放大倍数
            var zoomSize = (double)physicalScreenHeight / SystemParameters.PrimaryScreenHeight;

            return zoomSize;
        }

        //运行ctrl+v
        public static void Paste() { 
            SendKeys.SendWait("^{v}");
        }
        //运行ctrl+c
        public static void Copy() { 
            SendKeys.SendWait("^{c}");
        }

        //设置剪切板内容
        public static void SetClipboardData(object data) { 
            System.Windows.Forms.Clipboard.SetDataObject(data);
        }

        //复制文件或者文件夹
        public static void SetFileOrDirToClipBoard(string[] fileOrDirPaths) { 
            System.Collections.Specialized.StringCollection strcoll = new System.Collections.Specialized.StringCollection(); //收集路径
            foreach(string path in fileOrDirPaths) {
                strcoll.Add(path);
            }
            System.Windows.Forms.Clipboard.SetFileDropList(strcoll);
        }
        
    }
}
